RecyclerView基本概念:

RecyclerView是Android 5.0提出的新UI控件,位于support-v7包中,可以通过在build.gradle中添加
compile 'com.android.support:recyclerview-v7:24.2.1'导入。
RecyclerView的官方定义如下:
A flexible view for providing a limited window into a large data set.

RecyclerView 必知必会 [RecyclerView 必知必会]

RecyclerView的标准实现步骤如下:

  • 创建Adapter:创建一个继承RecyclerView.Adapter的Adapter类(VH是ViewHolder的类名),记为NormalAdapter。
  • 创建ViewHolder:在NormalAdapter中创建一个继承RecyclerView.ViewHolder的静态内部类,记为VH。ViewHolder的实现和ListView的ViewHolder实现几乎一样。
  • 在NormalAdapter中实现:VH onCreateViewHolder(ViewGroup parent, int viewType): 映射Item Layout Id,创建VH并返回。
1
2
3
4
需要注意的是在onCreateViewHolder()中,映射Layout必须为
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_1, parent, false);
而不能是:
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_1, null);
* void onBindViewHolder(VH holder, int position): 为holder设置指定数据。
* int getItemCount(): 返回Item的个数。

可以看出,RecyclerView将ListView中getView()的功能拆分成了onCreateViewHolder()和onBindViewHolder()。
创建完Adapter,接着对RecyclerView进行设置,一般来说,需要为RecyclerView进行四大设置,也就是后文说的四大组成:

Adapter(必选)

为了创建一个RecyclerView的Adapter,每次我们都需要去做重复劳动,包括重写onCreateViewHolder(),getItemCount()、创建ViewHolder,并且实现过程大同小异,因此万能适配器出现了,他能通过以下方式快捷地创建一个Adapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{
//创建子项item的布局
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
HomeActivity.this).inflate(R.layout.item_home, parent,
false));
return holder;
}
//给控件设置数据
@Override
public void onBindViewHolder(MyViewHolder holder, int position)
{
holder.tv.setText(mDatas.get(position));
}
//子项item的数量
@Override
public int getItemCount()
{
return mDatas.size();
}
class MyViewHolder extends ViewHolder
{
TextView tv;
public MyViewHolder(View view)
{
super(view);
tv = (TextView) view.findViewById(R.id.id_num);
}
}
}
}

Layout Manager(必选)

RecyclerView.LayoutManager吧,这是一个抽象类,好在系统提供了3个实现类:

  1. LinearLayoutManager 现行管理器,支持横向、纵向。
  2. GridLayoutManager 网格布局管理器
  3. StaggeredGridLayoutManager 瀑布就式布局管理器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));
    //ListView形式上下滑动:
    mMain_recyclerview.setLayoutManager(new LinearLayoutManager(this));
    //左右滑动:
    LinearLayoutManager magager = new LinearLayoutManager(this);
    magager.setOrientation(LinearLayoutManager.HORIZONTAL);
    //Grid形式上下滑动:
    GridLayoutManager layoutManager = new GridLayoutManager(this,4);
    //Grid形式左右滑动:
    GridLayoutManager layoutManager = new GridLayoutManager(this, 4);
    layoutManager.setOrientation(GridLayoutManager.HORIZONTAL);
    //瀑布流形式上下滑动:
    StaggeredGridLayoutManager layoutManager = newStaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL);
    //瀑布流形式左右滑动:
    StaggeredGridLayoutManager layoutManager = newStaggeredGridLayoutManager(4, StaggeredGridLayoutManager.HORIZONTAL);

Item Decoration(可选,默认为空)

mRecyclerView.addItemDecoration()
该方法的参数为RecyclerView.ItemDecoration,该类为抽象类,官方目前并没有提供默认的实现类
我们调用mRecyclerView.addItemDecoration()方法添加decoration的时候,RecyclerView在绘制的时候,去会绘制decorator,即调用该类的onDraw和onDrawOver方法,
onDraw方法先于drawChildren 绘制分割线。
onDrawOver在drawChildren之后,一般我们选择复写其中一个即可。
getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator。设置分割线的宽、高。
首先看构造函数,构造函数中获得系统属性android:listDivider,该属性是一个Drawable对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static abstract class ItemDecoration {
public void onDraw(Canvas c, RecyclerView parent, State state) {
onDraw(c, parent);
}
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
onDrawOver(c, parent);
}
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
parent);
}
@Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}

Item Animator(可选,默认为DefaultItemAnimator)

1
2
// 设置item动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());

多布局

  1. 实现多布局最核心的方法就是在Adapter中重写getItemViewType方法

    1
    2
    3
    4
    5
    6
    7
    8
    @Override
    public int getItemViewType(int position) {
    if (mNewsBeanList.get(position).getThumbnail_pic_s03() == null) {
    return IMAGE_ONLY_ONE;
    } else {
    return IMAGE_TWOORTHREE;
    }
    }
  2. 在onCreateViewHolder方法中第二个参数对应的就是上面方法返回的值,我们根据值的不同,填充不同的布局

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    if (viewType == IMAGE_TWOORTHREE) {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.news_imagethree_item, viewGroup, false);
    ImageThreeViewHolder viewHolder = new ImageThreeViewHolder(view);
    return viewHolder;
    } else {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.news_imageonly_item, viewGroup, false);
    ImageOnlyOneViewHolder viewHolder = new ImageOnlyOneViewHolder(view);
    return viewHolder;
    }
    }
  3. 不同的布局需要不同的ViewHolder

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    static class ImageThreeViewHolder extends RecyclerView.ViewHolder {
    private TextView mTv_title;
    private ImageView mIv_image01;
    private ImageView mIv_image02;
    private ImageView mIv_image03;
    private TextView mTv_company;
    private TextView mTv_time;
    private View mItemView;
    public ImageThreeViewHolder(View itemView) {
    super(itemView);
    mItemView = itemView;
    mTv_title = itemView.findViewById(R.id.tv_title);
    mIv_image01 = itemView.findViewById(R.id.iv_image01);
    mIv_image02 = itemView.findViewById(R.id.iv_image02);
    mIv_image03 = itemView.findViewById(R.id.iv_image03);
    mTv_company = itemView.findViewById(R.id.tv_company);
    mTv_time = itemView.findViewById(R.id.tv_time);
    }
    }
    static class ImageOnlyOneViewHolder extends RecyclerView.ViewHolder {
    private View mItemView;
    private TextView mTv_title;
    private TextView mTv_company;
    private TextView mTv_time;
    private ImageView mIv_image01;
    public ImageOnlyOneViewHolder(View itemView) {
    super(itemView);
    mItemView = itemView;
    mTv_title = itemView.findViewById(R.id.tv_title);
    mTv_company = itemView.findViewById(R.id.tv_company);
    mTv_time = itemView.findViewById(R.id.tv_time);
    mIv_image01 = itemView.findViewById(R.id.iv_image01);
    }
    }
  4. onBindViewHolder方法中的第一个参数对应不同的viewholder,我们通过判断,来进行每个元素的写入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ublic void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
    if (viewHolder instanceof ImageThreeViewHolder) {
    ((ImageThreeViewHolder) viewHolder).mTv_title.setText(mNewsBeanList.get(position).getTitle());
    ((ImageThreeViewHolder) viewHolder).mTv_company.setText(mNewsBeanList.get(position).getAuthor_name());
    ((ImageThreeViewHolder) viewHolder).mTv_time.setText(mNewsBeanList.get(position).getDate());
    Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s()).into(((ImageThreeViewHolder) viewHolder).mIv_image01);
    Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s02()).into(((ImageThreeViewHolder) viewHolder).mIv_image02);
    Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s03()).into(((ImageThreeViewHolder) viewHolder).mIv_image03);
    } else if (viewHolder instanceof ImageOnlyOneViewHolder) {
    ((ImageOnlyOneViewHolder) viewHolder).mTv_title.setText(mNewsBeanList.get(position).getTitle());
    ((ImageOnlyOneViewHolder) viewHolder).mTv_company.setText(mNewsBeanList.get(position).getAuthor_name());
    ((ImageOnlyOneViewHolder) viewHolder).mTv_time.setText(mNewsBeanList.get(position).getDate());
    Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s()).into(((ImageOnlyOneViewHolder) viewHolder).mIv_image01);
    }
    }

下拉刷新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Override
private void initRefresh() {
srRefresh.setColorSchemeResources(R.color.colorPrimary);
srRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshFruits();
}
});
}
private void refreshFruits() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
initFruits();
adapter.notifyDataSetChanged();
srRefresh.setRefreshing(false);
}
});
}
}).start();
}
private void initFruits() {
fruitList.clear(); for (int i = 0; i < 50; i++) {
Random random = new Random();
int index = random.nextInt(fruits.length);
fruitList.add(fruits[index]);
}
}

上拉加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (adapter.isFadeTips() == false && lastVisibleItem + 1 == adapter.getItemCount()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
}
}, 500);
}
if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
}
}, 500);
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
}
});